package com.qfedu.vhr.framework.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qfedu.vhr.common.RespBean;
import com.qfedu.vhr.framework.entity.HrDetails;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;

import java.io.IOException;

/**
 * @author baize
 * @date 2023/1/6
 * @site www.qfedu.com
 */
@Configuration
public class SecurityConfig {

    @Autowired
    MyFilterInvocationSecurityMetadataSource myFilterInvocationSecurityMetadataSource;

    @Autowired
    MyAccessDecisionManager myAccessDecisionManager;

    @Bean
    WebSecurityCustomizer webSecurityCustomizer() {
        return new WebSecurityCustomizer() {
            @Override
            public void customize(WebSecurity web) {
                web.ignoring().requestMatchers("/css/**", "/fonts/**", "/js/**", "/index.html", "/favicon.ico");
            }
        };
    }

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
//                .requestMatchers("/**")
//                .authenticated()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        object.setSecurityMetadataSource(myFilterInvocationSecurityMetadataSource);
                        object.setAccessDecisionManager(myAccessDecisionManager);
                        return object;
                    }
                })
                .and()
                .formLogin()
                .loginProcessingUrl("/login")
                .successHandler((req, resp, auth) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    HrDetails principal = (HrDetails) auth.getPrincipal();
                    principal.setPassword(null);
                    RespBean respBean = RespBean.ok("登录成功", principal);
                    resp.getWriter().write(new ObjectMapper().writeValueAsString(respBean));
                })
                .failureHandler((req, resp, e) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    RespBean respBean = RespBean.error("登录失败");
                    if (e instanceof BadCredentialsException) {
                        respBean.setMessage("用户名或者密码输入错误，登录失败");
                    } else if (e instanceof DisabledException) {
                        respBean.setMessage("账户被禁用，登录失败");
                    }
                    resp.getWriter().write(new ObjectMapper().writeValueAsString(respBean));
                })
                .permitAll()
                .and()
                .csrf().disable()
                .exceptionHandling()
                .authenticationEntryPoint((req, resp, auth) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    RespBean respBean = RespBean.error("尚未登录，请先登录");
//                    respBean.setStatus(401);
                    resp.setStatus(401);
                    resp.getWriter().write(new ObjectMapper().writeValueAsString(respBean));
                })
                //当权限不足的时候，抛出异常，会在这里被捕获
                //即 com.qfedu.vhr.framework.config.MyAccessDecisionManager.decide 方法抛出的异常，在这里处理
                .accessDeniedHandler((req, resp, e) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    RespBean respBean = RespBean.error(e.getMessage());
                    resp.getWriter().write(new ObjectMapper().writeValueAsString(respBean));
                })
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler((req, resp, auth) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    RespBean respBean = RespBean.ok("注销成功");
                    resp.getWriter().write(new ObjectMapper().writeValueAsString(respBean));
                });
        return http.build();
    }
}
